import tkinter as tk
from tkinter import scrolledtext
import socket
import threading
import time
from datetime import datetime
import queue
import binascii

class TTSController:
    def __init__(self, root):
        self.root = root
        self.root.title("语音播放")
        self.root.geometry("800x600")
        
        # 创建数据队列
        self.send_queue = queue.Queue(maxsize=100)
        self.data_queue = queue.Queue(maxsize=100)
        
        # TCP客户端连接变量
        self.client = None
        
        # 创建界面控件
        self.create_widgets()
        
        # 启动UI更新线程
        self.start_ui_update_thread()
    
    def create_widgets(self):
        # IP地址和端口输入区域
        tk.Label(self.root, text="IP：").place(x=48, y=26)
        self.txt_ip = tk.Entry(self.root)
        self.txt_ip.insert(0, "192.168.1.65")
        self.txt_ip.place(x=88, y=26)
        
        tk.Label(self.root, text="Port：").place(x=269, y=26)
        self.port = tk.Entry(self.root, width=10)
        self.port.insert(0, "50000")
        self.port.place(x=319, y=26)
        
        # 连接和关闭按钮
        self.connect_btn = tk.Button(self.root, text="连接", command=self.connect)
        self.connect_btn.place(x=418, y=26)
        
        self.close_btn = tk.Button(self.root, text="关闭", command=self.close)
        self.close_btn.place(x=479, y=26)
        
        # 播放文字区域
        tk.Label(self.root, text="播放文字").place(x=32, y=85)
        self.send_txt = tk.Entry(self.root, width=40)
        self.send_txt.place(x=88, y=81)
        
        self.send_btn = tk.Button(self.root, text="发送", command=self.send_text)
        self.send_btn.place(x=431, y=81)
        
        # 日志显示区域
        self.txt_log = scrolledtext.ScrolledText(self.root, width=60, height=15)
        self.txt_log.place(x=56, y=151)
        
        # TTS参数控制区域
        self.create_tts_control_panel()
    
    def create_tts_control_panel(self):
        # TTS控制面板
        control_frame = tk.LabelFrame(self.root, text="TTS控制面板", width=500, height=700)
        control_frame.place(x=520, y=151)
        
        # 发音人选择
        tk.Label(control_frame, text="发音人:").place(x=10, y=10)
        self.voice_var = tk.StringVar(value="3")
        voices = [("男声(尹小坚)", "3"), ("男声(易小强)", "4"), 
                  ("女声(田蓓蓓)", "5"), ("唐老鸭", "6"), ("女童声", "7")]
        y_pos = 20
        for text, value in voices:
            tk.Radiobutton(control_frame, text=text, variable=self.voice_var, 
                           value=value).place(x=70, y=y_pos)
            y_pos += 25
        
        # 语速控制
        tk.Label(control_frame, text="语速:").place(x=10, y=250)
        self.speed_var = tk.StringVar(value="5")
        self.speed_scale = tk.Scale(control_frame, from_=0, to=10, orient=tk.HORIZONTAL,
                                    variable=self.speed_var, length=200)
        self.speed_scale.place(x=70, y=230)
        
        # 语调控制
        tk.Label(control_frame, text="语调:").place(x=10, y=300)
        self.pitch_var = tk.StringVar(value="5")
        self.pitch_scale = tk.Scale(control_frame, from_=0, to=10, orient=tk.HORIZONTAL,
                                     variable=self.pitch_var, length=200)
        self.pitch_scale.place(x=70, y=280)
        
        # 音量控制
        tk.Label(control_frame, text="音量:").place(x=10, y=350)
        self.volume_var = tk.StringVar(value="5")
        self.volume_scale = tk.Scale(control_frame, from_=0, to=10, orient=tk.HORIZONTAL,
                                      variable=self.volume_var, length=200)
        self.volume_scale.place(x=70, y=330)
        
        # 数字处理策略
        tk.Label(control_frame, text="数字处理:").place(x=10, y=380)
        self.number_var = tk.StringVar(value="0")
        number_options = [("自动判断", "0"), ("数字做号码", "1"), ("数字做数值", "2")]
        x_pos = 80
        for text, value in number_options:
            tk.Radiobutton(control_frame, text=text, variable=self.number_var, 
                          value=value).place(x=x_pos, y=380)
            x_pos += 80
        
        # 其他设置 - 复选框
        self.pinyin_var = tk.BooleanVar(value=False)
        tk.Checkbutton(control_frame, text="识别汉语拼音", 
                       variable=self.pinyin_var).place(x=10, y=410)
        
        self.punctuation_var = tk.BooleanVar(value=False)
        tk.Checkbutton(control_frame, text="朗读标点符号", 
                       variable=self.punctuation_var).place(x=150, y=410)
        
        # 应用设置按钮
        self.apply_btn = tk.Button(control_frame, text="应用设置", command=self.apply_settings)
        self.apply_btn.place(x=100, y=540)
    
    def apply_settings(self):
        """应用TTS设置"""
        settings = ""
        # 发音人
        settings += f"[m{self.voice_var.get()}]"
        # 语速
        settings += f"[s{self.speed_var.get()}]"
        # 语调
        settings += f"[t{self.pitch_var.get()}]"
        # 音量
        settings += f"[v{self.volume_var.get()}]"
        # 数字处理
        settings += f"[n{self.number_var.get()}]"
        # 识别拼音
        settings += f"[i{1 if self.pinyin_var.get() else 0}]"
        # 标点朗读
        settings += f"[b{1 if self.punctuation_var.get() else 0}]"
        
        try:
            # 将设置发送到队列
            self.send_queue.put("#" + settings)
            self.data_queue.put("发送设置：#" + settings)
        except Exception as e:
            print(f"应用设置错误: {e}")
    
    def set_area(self, text):
        """更新日志区域"""
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.txt_log.insert(tk.END, f"{current_time}   {text}\n")
        self.txt_log.see(tk.END)  # 自动滚动到最新内容
    
    def start_ui_update_thread(self):
        """启动UI更新线程"""
        def update_ui():
            while True:
                try:
                    message = self.data_queue.get(timeout=0.1)
                    # 使用after方法在主线程中更新UI
                    self.root.after(0, lambda msg=message: self.set_area(msg))
                except queue.Empty:
                    pass
                except Exception as e:
                    print(f"UI更新错误: {e}")
                time.sleep(0.1)
        
        ui_thread = threading.Thread(target=update_ui, daemon=True)
        ui_thread.start()
    
    def connect(self):
        """连接到服务器"""
        try:
            if self.client and self.client.fileno() != -1:
                self.data_queue.put("已经连接")
                return
            
            ip = self.txt_ip.get()
            port = int(self.port.get())
            
            # 创建TCP连接
            self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.client.connect((ip, port))
            
            self.data_queue.put("连接成功")
            
            # 启动接收线程
            read_thread = threading.Thread(target=self.read_data_thread, daemon=True)
            read_thread.start()
            
            # 启动发送线程
            send_thread = threading.Thread(target=self.send_data_thread, daemon=True)
            send_thread.start()
            
        except Exception as e:
            self.data_queue.put(f"连接失败: {str(e)}")
            print(f"连接错误: {e}")
    
    def close(self):
        """关闭连接"""
        if self.client:
            try:
                self.client.close()
                self.client = None
                # 发送空字符串以结束发送线程的等待
                self.send_queue.put("")
                self.data_queue.put("关闭连接")
            except Exception as e:
                print(f"关闭连接错误: {e}")
    
    def send_text(self):
        """发送文本到TTS设备"""
        try:
            text = self.send_txt.get()
            if text:
                self.send_queue.put("#" + text)
                self.data_queue.put("发送：#" + text)
        except Exception as e:
            print(f"发送文本错误: {e}")
    
    def read_data_thread(self):
        """数据接收线程"""
        try:
            while self.client:
                if not self.client or self.client.fileno() == -1:
                    self.data_queue.put("退出接收线程")
                    return
                
                # 接收数据
                try:
                    data = self.client.recv(1024)
                    if data:
                        # 将数据转换为十六进制字符串
                        hex_data = binascii.hexlify(data).decode().upper()
                        
                        # 判断特定响应
                        if hex_data == "4F4B":
                            self.data_queue.put("收到回复！OK")
                        elif hex_data == "0800":
                            self.data_queue.put("收到回复！OL")
                        else:
                            self.data_queue.put(f"收到回复：{hex_data}")
                    else:
                        self.data_queue.put("数据读取完毕！")
                        self.close()
                        return
                except Exception as e:
                    self.data_queue.put(f"接收错误: {str(e)}")
                    self.close()
                    return
                
                time.sleep(0.1)
        except Exception as e:
            self.data_queue.put(f"接收线程错误: {str(e)}")
            return
    
    def send_data_thread(self):
        """数据发送线程"""
        try:
            while True:
                if not self.client:
                    self.data_queue.put("退出发送线程")
                    return
                
                message = self.send_queue.get()
                
                if not message:  # 空消息用于结束线程
                    self.data_queue.put("退出发送线程")
                    return
                
                if not self.client or self.client.fileno() == -1:
                    self.data_queue.put("退出发送线程")
                    return
                
                # 编码并发送数据
                encoded_bytes = message.encode('gb2312')
                self.client.sendall(encoded_bytes)
                
                time.sleep(0.5)
        except Exception as e:
            self.data_queue.put(f"发送线程错误: {str(e)}")
            return
    
    @staticmethod
    def hex_string_to_byte_array(hex_string):
        """十六进制字符串转换为字节数组"""
        hex_string = hex_string.replace(" ", "")
        length = len(hex_string)
        if length % 2 != 0:
            length += 1
            hex_string = "0" + hex_string
        
        return binascii.unhexlify(hex_string)
    
    @staticmethod
    def bytes_to_hex(data):
        """字节数组转换为十六进制字符串"""
        return binascii.hexlify(data).decode().upper()


def main():
    root = tk.Tk()
    app = TTSController(root)
    root.mainloop()

if __name__ == "__main__":
    main()

# 功能说明_扩展实现

# 1. 发音人选择 [m*] - 允许选择不同的声音(男声、女声、唐老鸭效果等)
# 2. 语速控制 [s*] - 0-10级调节语速
# 3. 语调控制 [t*] - 0-10级调节语调
# 4. 音量控制 [v*] - 0-10级调节音量
# 5. 数字处理策略 [n*] - 选择自动判断/号码处理/数值处理
# 6. 识别汉语拼音 [i*] - 启用/禁用拼音识别
# 7. 标点符号朗读 [b*] - 启用/禁用标点朗读

# # 界面与功能说明
# 1. 主界面包含TCP连接控制区域、文本输入区域和日志显示区域
# 2. 右侧添加了TTS控制面板，可调整所有语音参数
# 3. 通过使用线程分离网络IO和界面更新，保证了界面的响应性
# 4. 实现了双向通信，可接收设备反馈信息

# 使用说明_操作方法
# # 使用方法

# 1. 运行程序后，输入设备的IP地址和端口号
# 2. 点击"连接"按钮连接到语音模块
# 3. 在TTS控制面板上设置所需的参数：
#    - 选择发音人
#    - 调整语速、语调和音量
#    - 设置数字处理策略
#    - 选择是否识别拼音和标点符号
# 4. 点击"应用设置"按钮发送设置到设备
# 5. 在文本输入框中输入要播放的文字
# 6. 点击"发送"按钮将文字发送到设备播放
# 7. 使用完毕后点击"关闭"按钮断开连接

# # 高级用法
# 可以在文本中直接嵌入控制标记，例如：
# - [p500]插入500毫秒的停顿
# - [=ni3]强制为前一个汉字指定读音"ni3"
# - [z1]#处理韵律标注*实现更自然的语音效果